//
// Created by LvenLiu on 2022/8/16.
//

#ifndef FFMPEGDEMO_SAFEQUEUE_H
#define FFMPEGDEMO_SAFEQUEUE_H

#include <queue>
#include <pthread.h>

using namespace std;

// 加锁的队列
template<class T>
class SafeQueue {
    // 回调声明
    typedef void (*ReleaseCallback)(T *);

private:
    // 生产消费队列
    queue<T> queue;
    // 锁
    pthread_mutex_t mutex;
    // 等待 唤醒
    pthread_cond_t cond;
    // 工作状态
    int work;
    // 销毁回调
    ReleaseCallback callback;


public:
    SafeQueue() {
        // 初始化
        pthread_mutex_init(&mutex, 0);
        pthread_cond_init(&cond, 0);
    }

    ~SafeQueue() {
        // 销毁 栈会自动调用  new（堆） 要调用delete才会走析构
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&cond);
    }

    /**
     * 添加元素，尾加
     */
    void offer(T &item) {
        // 加锁
        pthread_mutex_lock(&mutex);

        if (work) {
            // 工作状态
            queue.push(item);
            // 唤醒
            pthread_cond_signal(&cond);
        } else {
            // 回收
            if (callback) {
                // 外界回收
                callback(&item);
            }
        }
        // 释放锁
        pthread_mutex_unlock(&mutex);
    }

    /**
     * 取元素
     * @param item
     * @return 1 success
     */
    int pull(T &item) {
        // 加锁
        pthread_mutex_lock(&mutex);
        int r = 0;
        while (work && queue.empty()) {
            // 等待
            pthread_cond_wait(&cond, &mutex);
        }

        if (!queue.empty()) {
            // 取前面的
            item = queue.front();
            queue.pop();
            r = 1;
        }

        // 释放锁
        pthread_mutex_unlock(&mutex);
        return r;
    }

    int size() {
        return queue.size();
    }

    bool empty() {
        return queue.empty();
    }

    /**
     * 设置工作状态
     * @param work 0 not work
     */
    void setWork(int work) {
        // 加锁
        pthread_mutex_lock(&mutex);
        this->work = work;
        // 唤醒一下
        pthread_cond_signal(&cond);
        // 释放锁
        pthread_mutex_unlock(&mutex);
    }

    void clear() {
        // 加锁
        pthread_mutex_lock(&mutex);

        for (int i = 0; i < queue.size(); ++i) {
            T item = queue.front();
            // 从队列移除
            queue.pop();
            // 回收
            if (callback) {
                callback(&item);
            }
        }
        // 唤醒
        pthread_cond_signal(&cond);
        // 释放锁
        pthread_mutex_unlock(&mutex);
    }

    /**
     * 停止工作，并清除
     */
    void stopAndClear() {
        setWork(0);
        clear();
    }

    /**
     * 设置回收监听
     */
    void setReleaseCallback(ReleaseCallback callback) {
        this->callback = callback;
    }
};


#endif //FFMPEGDEMO_SAFEQUEUE_H
